package com.vita.bduck.logger;

import android.text.TextUtils;
import com.vita.bduck.common.SystemUtils;
import com.vita.bduck.logger.helps.Utils;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

/**
 * 日志工具类
 * Created with IntelliJ IDEA.
 * User: Vita Hao
 * Date: 13-6-19
 * Time: 上午9:55
 * To change this template use File | Settings | File Templates.
 */
public class Log implements Logger {

    private static final long serialVersionUID = -1227274521521287937L;

    private static final String TAG = LogConstant.LOG_TAG;

    private final int LOG_NULL = LogConstant.LOG_NULL;    // 输出未捕获异常，其他都不输出
    private final int LOG_I = LogConstant.LOG_I;    // info
    private final int LOG_W = LogConstant.LOG_W;    // warning
    private final int LOG_V = LogConstant.LOG_V;    // verbose
    private final int LOG_D = LogConstant.LOG_D;    // debug
    private final int LOG_E = LogConstant.LOG_E;    // error
    private final int LOG_WTF = LogConstant.LOG_WTF;    // what a terrible failure

    /**
     * 为log 命名
     */
    private static String name;
    /**
     * 日志写出的路径
     */
    private static String logPath = LogCrashHandler.logPath;

    /**
     * 是否为DEBUG模式
     */
    private static boolean mIsDebug = LogCrashHandler.mIsDebug;

    /**
     * 是否显示在LogCat上，
     */
    private static boolean mIsInLogCat = LogCrashHandler.mIsInLogCat;

    /**
     * 输出log flags,默认输出debug, warning, error
     */
    private static int mFlags = LogCrashHandler.mFlags;

    /**
     * 是否写文件
     */
    private static boolean mIsInFlie = LogCrashHandler.mIsInFile;

    /**
     * 允许同包被实例化
     */
    Log(String name) {
        this.name = name;
    }

    /**
     * 获取日志写出路径
     *
     * @return
     */
    public static String getLogPath() {
        return logPath;
    }

    /**
     * 设置输出log类型
     *
     * @param flags
     * @return
     */
    public static int setFlags(int flags) {
        int ret = mFlags;
        mFlags = flags;
        return ret;
    }

    /**
     * 获取输出 log类型
     *
     * @return
     */
    public static int getFlags() {
        return mFlags;
    }

    /**
     * 写到文件中
     */
    protected static void writeToLog(String level, String Tag, String Msg) {
        if (!TextUtils.isEmpty(logPath)) {
            LogWritter logWritter = LogWritter.getInstance();
            if (logWritter != null) {
                logWritter.toLog(logPath, level, Tag, Msg);
            } else {
                android.util.Log.w(TAG, "LogWritter is null");
            }
        } else {
            android.util.Log.w(TAG, "Log path is null");
        }
    }

    /**
     * 写到文件中
     */
    private static void writeToLog(String level, String Tag) {
        writeToLog(level, Tag, "");
    }

    /**
     * 是否存在SD卡
     *
     * @return
     */
    public static boolean existSDCard() {
        if (android.os.Environment.getExternalStorageState().equals(
                android.os.Environment.MEDIA_MOUNTED)) {
            return true;
        } else {
            return false;
        }
    }


    @Override
    public String getName() {
        if (name == null)
            return LogConstant.LOG_TAG;
        return name;
    }

    @Override
    public boolean isTraceEnabled() {
        return android.util.Log.isLoggable(getName(), android.util.Log.VERBOSE);
    }

    @Override
    public void v(String msg) {
        verbose(msg,null);
    }

    @Override
    public void v(String format, Object arg) {
       verbose(Utils.format(format,arg,null),null);
    }

    @Override
    public void v(String format, Object arg1, Object arg2) {
     verbose(Utils.format(format,arg1,arg2),null);
    }

    @Override
    public void v(String format, Object[] argArray) {
      verbose(Utils.format(format,argArray),null);
    }

    @Override
    public void v(String msg, Throwable t) {
        verbose(msg,t);
    }

    private void verbose(String msg,Throwable t){
        if (mIsDebug && ((mFlags & LOG_V) == LOG_V)) {
            if (mIsInLogCat) {
                android.util.Log.v(getName(), msg, t);
            }

            if (mIsInFlie){
                // write to log file
                StringBuilder sb = new StringBuilder();
                sb.append("[v:]\t");
                sb.append("Tag:");
                sb.append(getName());
                writeToLog("v", sb.toString(), msg);
            }

        }
    }

    @Override
    public boolean isDebugEnabled() {
        return android.util.Log.isLoggable(getName(), android.util.Log.DEBUG);
    }

    @Override
    public void d(String msg) {
          debug(msg,null);
    }

    @Override
    public void d(String format, Object arg) {
      debug(Utils.format(format,arg,null),null);
    }

    @Override
    public void d(String format, Object arg1, Object arg2) {
        debug(Utils.format(format,arg1,arg2),null);
    }

    @Override
    public void d(String format, Object[] argArray) {
       debug(Utils.format(format,argArray),null);
    }

    @Override
    public void d(String msg, Throwable t) {
        debug(msg,t);
    }

    private void debug(String msg, Throwable t){
        if (mIsDebug && ((mFlags & LOG_D) == LOG_D)) {
            if (mIsInLogCat) {
                android.util.Log.d(getName(), msg, t);
            }

            if (mIsInFlie){
                // write to log file
                StringBuilder sb = new StringBuilder();
                sb.append("[d:]\t");
                sb.append("Tag:");
                sb.append(getName());
                writeToLog("d", sb.toString(), msg);
            }
        }
    }

    @Override
    public boolean isInfoEnabled() {
        return android.util.Log.isLoggable(getName(), android.util.Log.INFO);
    }

    @Override
    public void i(String msg) {
        info(msg);
    }

    @Override
    public void i(String format, Object arg) {
        info(Utils.format(format, arg, null));
    }

    @Override
    public void i(String format, Object arg1, Object arg2) {
        info(Utils.format(format, arg1, arg2));
    }

    @Override
    public void i(String format, Object[] argArray) {
        info(Utils.format(format, argArray));
    }

    @Override
    public void i(String msg, Throwable t) {
        info(msg, t);
    }

    private void info(String msg) {
        info(msg, null);
    }

    private void info(String msg, Throwable t) {
        if (mIsDebug && ((mFlags & LOG_I) == LOG_I)) {
            if (mIsInLogCat) {
                android.util.Log.i(getName(), msg, t);
            }

            if (mIsInFlie) {
                // write to log file
                StringBuilder sb = new StringBuilder();
                sb.append("[i:]\t");
                sb.append("Tag:");
                sb.append(getName());
                writeToLog("i", sb.toString(), msg);
            }

        }
    }

    @Override
    public boolean isWarnEnabled() {
        return android.util.Log.isLoggable(getName(), android.util.Log.WARN);
    }

    @Override
    public void w(String msg) {
        warn(msg);
    }

    @Override
    public void w(String format, Object arg) {
        warn(Utils.format(format, arg, null));
    }

    @Override
    public void w(String format, Object[] argArray) {
        warn(Utils.format(format, argArray));
    }

    @Override
    public void w(String format, Object arg1, Object arg2) {
        warn(Utils.format(format, arg1, arg2));
    }


    @Override
    public void w(String msg, Throwable t) {
        warn(msg, t);
    }

    private void warn(String msg) {
        warn(msg, null);
    }

    private void warn(String msg, Throwable t) {
        if (mIsDebug && ((mFlags & LOG_W) == LOG_W)) {
            if (mIsInLogCat) {
                android.util.Log.w(getName(), msg, t);
            }

            if (mIsInFlie) {
                // write to log file
                StringBuilder sb = new StringBuilder();
                sb.append("[w:]\t");
                sb.append("Tag:");
                sb.append(getName());
                writeToLog("w", sb.toString(), msg);
            }
        }
    }

    @Override
    public boolean isErrorEnabled() {
        return android.util.Log.isLoggable(getName(), android.util.Log.ERROR);
    }

    @Override
    public void e(String msg) {
        error(msg);
    }

    @Override
    public void e(String format, Object arg) {
        error(Utils.format(format, arg, null));
    }

    @Override
    public void e(String format, Object arg1, Object arg2) {
        error(Utils.format(format, arg1, arg2));
    }

    @Override
    public void e(String format, Object[] argArray) {
        error(Utils.format(format, argArray));
        //To change body of implemented methods use File | Settings | File Templates.
    }

    private void error(String msg) {
        error(msg, null);
    }

    private void error(String msg, Throwable t) {
        if (mIsDebug && ((mFlags & LOG_E) == LOG_E)) {

            if (mIsInLogCat) {
                android.util.Log.e(getName(), msg,t);
            }

            // write to log file
            StringBuilder sb = new StringBuilder();
            sb.append("[e:]\t");
            sb.append("Tag:");
            sb.append(getName());
            writeToLog("e", sb.toString(), msg);
        }
    }

    @Override
    public void e(String msg, Throwable t) {
        error(msg, t);
    }

    @Override
    public boolean isWTFEnable() {
        return android.util.Log.isLoggable(getName(), LOG_WTF);
    }

    @Override
    public void wtf(String msg, Throwable t) {
        wtf(msg, t);
    }

    @Override
    public void wtf(String format, Object[] argArray) {
        wtf(Utils.format(format, argArray));
    }

    @Override
    public void wtf(String format, Object arg1, Object arg2) {
        wtf(Utils.format(format, arg1, arg2));
    }

    @Override
    public void wtf(String format, Object arg) {
        wtf(Utils.format(format, arg, null));
    }

    @Override
    public void wtf(String msg) {
        wtfLog(msg);
    }

    private void wtfLog(String msg) {
        wtfLog(msg, null);
    }

    private void wtfLog(String msg, Throwable t) {
        if (mIsDebug && ((mFlags & LOG_WTF) == LOG_WTF)) {
            if (mIsInLogCat) {
                // 由于wtf是API8才有的方法，所以在此要用反射调用
                if (SystemUtils.hasFroyo()) {
                    try {
                        Class<?> c = Class.forName("android.util.Log");
                        Method m = c.getMethod("wtf", new Class[]{String.class, String.class, Throwable.class});
                        m.invoke(c, new Object[]{getName(), msg, t});
                    } catch (ClassNotFoundException e) {
                        e.printStackTrace();
                    } catch (SecurityException e) {
                        e.printStackTrace();
                    } catch (NoSuchMethodException e) {
                        e.printStackTrace();
                    } catch (IllegalArgumentException e) {
                        e.printStackTrace();
                    } catch (IllegalAccessException e) {
                        e.printStackTrace();
                    } catch (InvocationTargetException e) {
                        e.printStackTrace();
                    }
                }
            }

            if (mIsInFlie) {
                // write to log file
                StringBuilder sb = new StringBuilder();
                sb.append("[wtf:]\t");
                sb.append("Tag:");
                sb.append(getName());
                writeToLog(sb.toString(), msg);
            }
        }
    }

}
